﻿using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using UIOC.CodeAnalysis.Diagnostics;
using UIOC.CodeAnalysis.Extensions;

namespace UIOC.CodeAnalysis.Analyzers;

[DiagnosticAnalyzer(LanguageNames.CSharp)]
internal sealed class InstanceTypeAttributeAnalyzer : DiagnosticAnalyzer {

    public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
        => ImmutableArray.Create(InstanceTypeAttributeInheritanceDiagnostic.Rule);

    public override void Initialize(AnalysisContext context) {
        context.EnableConcurrentExecution();
        context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
        context.RegisterSyntaxNodeAction(AnalyzeInterfaceDeclaration, SyntaxKind.InterfaceDeclaration);
    }
    private void AnalyzeInterfaceDeclaration(SyntaxNodeAnalysisContext context) {
        var compilation = context.Compilation;
        var assembly = compilation.Assembly;
        if (assembly.IsIgnore()) {
            return;
        }

        if (context.Node is not InterfaceDeclarationSyntax interfaceDeclarationSyntax) {
            return;
        }

        var interfaceSymbol = context.SemanticModel.GetDeclaredSymbol(interfaceDeclarationSyntax);
        if (interfaceSymbol == null)
            return;

        var instanceTypeAttributeSymbol = compilation.GetTypeByMetadataName(AttributeFullNames.InstanceType);
        if (instanceTypeAttributeSymbol == null) {
            return;
        }

        var instanceTypeAttributeData = interfaceSymbol.GetAttributes(instanceTypeAttributeSymbol).FirstOrDefault();
        if (instanceTypeAttributeData == null) {
            return;
        }

        var baseInterfaceSymbol = interfaceSymbol.AllInterfaces.Where(@interface => @interface.GetAttributes(instanceTypeAttributeSymbol).Any()).FirstOrDefault();
        if (baseInterfaceSymbol == null) {
            return;
        }

        context.ReportDiagnostic(Diagnostic.Create(
            InstanceTypeAttributeInheritanceDiagnostic.Rule,
            instanceTypeAttributeData.ApplicationSyntaxReference?.GetSyntax(context.CancellationToken)?.GetLocation() ?? interfaceDeclarationSyntax.Identifier.GetLocation(),
            interfaceDeclarationSyntax.GetDeclaraionName(),
            baseInterfaceSymbol.CreateSimpleNameSyntax()
        ));
    }
}
